#include "server.h"
#include "read_config.h"

int start_http(void);

/************Global variables*********/
struct nas_user_table *table_header = 0;
struct table_chain *free_table_header;
struct table_chain *free_table_tail;
struct table_chain *auth_table_header;
struct table_chain *acct_table_header;
struct table_chain table_chain[MAX_TABLE_NUMBER];
pthread_mutex_t tablemutex = PTHREAD_MUTEX_INITIALIZER;
int count = 0;

udp_query_queue  *head;
udp_query_queue  *tail;
unsigned int queue_number;
pthread_mutex_t udp_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t udp_cond;
int Serv_UDP_Sock;

int do_radius_test = 0;
int do_radius_account = 0;
int num_config_pairs = -2;
const char *radius_server_ipv6 = 0;
const char *radius_server_ipv4 = 0;
const char *radius_reserve_server_ipv6 = 0;
const char *radius_reserve_server_ipv4 = 0;
const char *radius_shared_key = 0;
const char *radius_default_af = 0;
int radius_default_afnum = 0;
const char *local_server_ipv6 = 0;
const char *local_server_ipv4 = 0;
int set_user_type = -1;

int debug;

timer_queue queue;
#if USE_AES_AUTHENTICATION
struct aes_ctx aes;
#endif

const char server_cannot_account[] = "Reply-Message = \"Could not start account\"";
const char server_reply_timeout[] = "Reply-Message = \"Could not connect to radius server\"";
const char server_reply_auth_too_often[] = "Reply-Message = \"Authenticate too often, wait some time...\"";
const char server_reply_max_users[] = "Reply-Message = \"Server table is full\"";
const char nas_name[11] = "BeijingZpk";

int admin_control(SSL *ssl)
{
    int p;
    char reply[1000] = {0}, receive[1000] = {0};


    Vdebug(DEBUG_DATE, "[admin]Administrator logged in!");
    while (1)
    {
        memset(receive, 0 , 1000);
        memset(reply, 0 , 1000);
        if ((p = SSL_read(ssl, receive, 1000)) <= 0) break;
        Vdebug(DEBUG_DATE, "[admin]Receive command: %s, length: %d", receive, p);
        if (!strcmp(receive, "auth"))
        {
            admin_auth(reply);
            if (SSL_write(ssl, reply, 1000) <= 0)
                break;
            continue;
        }
        if (!strncmp(receive, "sendmessage", strlen("sendmessage")))
        {
            admin_sendmessage(reply, receive);
            if (SSL_write(ssl, reply, 1000) <= 0)
                break;
            continue;
        }
        if (!strncmp(receive, "setrate", strlen("setrate")))
        {
            admin_setrate(reply, receive);
            if (SSL_write(ssl, reply, 1000) <= 0)
                break;
            continue;
        }
        if (!strcmp(receive, "acct"))
        {
            admin_acct(reply);
            if (SSL_write(ssl, reply, 1000) <= 0)
                break;
            continue;
        }
        if (!strncmp(receive, "checkuser", strlen("checkuser")))
        {
            admin_checkuser(reply, receive);
            if (SSL_write(ssl, reply, 1000) <= 0)
                break;
            continue;
        }
        if (!strncmp(receive, "kickuser", strlen("kickuser")))
        {
            admin_kickuser(reply, receive);
            if (SSL_write(ssl, reply, 1000) <= 0)
                break;
            continue;
        }
        if (!strcmp(receive, "radius"))
        {
            admin_radius(reply);
            if (SSL_write(ssl, reply, 1000) <= 0)
                break;
            continue;
        }
        sprintf(reply, "Unknown command: %s", receive);
        Vdebug(DEBUG_DATE, "[admin]%s", reply);
        if (SSL_write(ssl, reply, 1000) <= 0)
            break;
        /*
        if (!strcmp(receive, "auth")) {
            admin_auth(reply);
            continue;
        }
        if (!strcmp(receive, "auth")) {
            admin_auth(reply);
            continue;
        }*/
    }
    return 0;
}

void translate_version(int v, char *s)
{
    int i[4] = {0};
    i[3] = v >> 24;
    i[2] = v << 8 >> 24;
    i[1] = v << 16 >> 24;
    i[0] = v << 24 >> 24;
    sprintf(s ,"%d.%d.%d.%d", i[3], i[2], i[1], i[0]);
}

void
radius_auth_user(SSL *ssl, struct table_chain *chain,
                 struct login_reply_server *server)
{
    int ret;
    char RadReply[UDP_PACKET_MAX_LENGTH] = {0};
    short *replylen = (short *)RadReply;
    USER_TYPE user_type;
    char *temp;

    *replylen = sizeof(RadReply);

    ret = rad_send_request(chain->table->name, chain->table->pass, chain, RadReply, &user_type);

	Vdebug(DEBUG_DATE, "[user login]Radius Auth for table%d: %s, result %d", chain->id, chain->table->name, ret);
	
    pthread_mutex_lock(&tablemutex);
	//MLog("Lock: user auth");
    switch (ret)
    {
    case -1:       //auth time out
        free_table(chain);
        pthread_mutex_unlock(&tablemutex);
		//MLog("UnLock: user auth");
        server->type = SERVER_AUTH_REJECT;
        ssl_send_server_reply(ssl, server, server_reply_timeout);
        break;
    case -2:
        free_table(chain);
        pthread_mutex_unlock(&tablemutex);
		//MLog("UnLock: user auth");
        server->type = SERVER_AUTH_REJECT;
        ssl_send_server_reply(ssl, server, server_cannot_account);
        break;
    case 2:     //auth succeed
        user_start_account(chain); 
		server->type = SERVER_AUTH_REPLY;
        temp = get_rad_var("Veno-Client-Down", RadReply, sizeof(RadReply) - 1);
        if (temp)
        {
            server->down_rate = atoi(temp);
            free(temp);
        }
        else
        {
            server->down_rate = 0;
        }
        temp = get_rad_var("Veno-Client-Up", RadReply, sizeof(RadReply) - 1);
        if (temp)
        {
            server->up_rate = atoi(temp);
            free(temp);
        }
        else
        {
            server->down_rate = 0;
        }
        if (set_user_type != -1)     // use type defined in configure file
        {
            server->user_type = set_user_type;
        }
        else server->user_type = user_type;

        chain->table->download_rate_limit = server->down_rate;
        chain->table->upload_rate_limit = server->up_rate;
        chain->table->user_type = server->user_type;
        memcpy(server->secret, chain->table->secret, UDP_PACKET_SECRET_KEY_LENGTH);
        server->table_id = chain->id;

		pthread_mutex_unlock(&tablemutex);
		//MLog("UnLock: user auth");

        temp = get_rad_var("Veno-Reply-Message", RadReply, sizeof(RadReply) - 1);
        if (temp)
        {
            ssl_send_server_reply(ssl, server, temp);
            free(temp);
        }
        else
        {
            ssl_send_server_reply(ssl, server, "");
        }
        break;    
    default:       //auth reject
        free_table(chain);
        pthread_mutex_unlock(&tablemutex);
		//MLog("UnLock: user auth");
        server->type = SERVER_AUTH_REJECT;
        ssl_send_server_reply(ssl, server, RadReply);
        break;
	}
}


void *ssl_thread(void * arg)
{
    char name[USER_NAME_LENGTH + 1] = {0}, pass[USER_PASS_LENGTH + 1] = {0}, mac[USER_MAC_LENGTH + 1] = {0};
    char ServerReply[UDP_PACKET_MAX_LENGTH] = {0};
    SSL *ssl = (SSL *)arg;
    struct sockaddr_storage From;
    unsigned int FromLen = 0;
    int sock,ret;
    char ipaddr[40] = {0};
    //char iptemp[200] = {0};
    struct login_reply_server *server;
    int version, login_type = -1;
    char v[10] = {0};
    struct table_chain *chain;
	struct login_request_client_200 client;

	char *buf;
	int p;		
	struct udp_query_queue *queue;
	char receive[UDP_PACKET_MAX_LENGTH] = {0};

    server = (struct login_reply_server *)ServerReply;
	memset(&client, 0, sizeof(struct login_request_client_200));
    memset(&From, 0, sizeof(struct sockaddr_storage));
    FromLen = sizeof(From);
    sock = SSL_get_fd(ssl);
    
    getpeername(sock, (struct sockaddr *)&From, &FromLen);
    print_ipaddr(ipaddr, From);
	Vdebug(DEBUG_STDOUT, "[user login]Thread (pid = %u) start, using sock %d, ip %s", (unsigned int)pthread_self(), sock, ipaddr);

	ret = ssl_accept_user((SSL *)arg, name, pass, mac, &version, &login_type, &client);
    if (ret < 0)
    {
		Vdebug(DEBUG_STDOUT, "[user login]Error accept user");
        goto thread_end;
    }
	if (ret == 2)   // client  keepalive  tcp
	{
		Vdebug(DEBUG_STDOUT, "[user login]User use tcp keepalive");
		if ((p = SSL_read(ssl, receive, UDP_PACKET_MAX_LENGTH)) <= 0)
			goto thread_end;
		if (p >= UDP_PACKET_MAX_LENGTH) 
			goto thread_end;

        buf = malloc(p);
        if (!buf)
        {
            goto thread_end;
        }
        memcpy(buf, receive, p);
        queue = malloc(sizeof(udp_query_queue));
        if (!queue)
        {
            free(buf);
            goto thread_end;
        }
        memset(queue , 0, sizeof(udp_query_queue));
        queue->buf = (char *)buf;
        queue->next = NULL;
        memcpy(&queue->From, &sock, sizeof(sock));
        queue->FromLen = 0;
        queue->packet_len = p;

        pthread_mutex_lock(&udp_mutex);
        queue_number++;
        queue->num = queue_number;
        if (!head)
        {
            head = queue;
            tail = queue;
            pthread_mutex_unlock(&udp_mutex);
            pthread_cond_signal(&udp_cond);
        }
        else
        {
            //assert(tail != NULL);
            tail->next = queue;
            tail = queue;
            pthread_mutex_unlock(&udp_mutex);
        }
		return NULL;
	}
    translate_version(version, v);

	Vdebug(DEBUG_DATE, "[user login]%s, from %s, mac %s, version %s, type %d, radius version %d", name, ipaddr, mac, v, login_type, client.radversion);

    switch (login_type)
    {
    case ADMIN_AUTH_REQUEST:
        if ((strncmp(name, NAS_ADMIN_NAME, strlen(NAS_ADMIN_NAME)) == 0) &&
                (strncmp(pass, NAS_ADMIN_PASS, strlen(NAS_ADMIN_PASS)) == 0))
        {
            server->type = ADMIN_AUTH_ACCEPT;
            ssl_send_server_reply(ssl, server, "Radclient1.0");
            admin_control(ssl);
        }
        else
        {
            server->type = ADMIN_AUTH_REJECT;
            ssl_send_server_reply(ssl, server, "Wrong credential.");
        }
        break;
    case CLIENT_REAUTH_REQUEST:
        Vdebug(DEBUG_DATE, "[user login]User reauth: %s", name);
       /* pthread_mutex_lock(&tablemutex);
		//MLog("Lock: user relogin");
        chain = acct_user_check(name, client.secret);
        if (chain)
        {
            if (chain->table->status != USER_ACCOUNTING)
            {
                Vdebug(DEBUG_DATE, "[user login]Deny relogin: %s, not accounting", name);
                server->type = SERVER_AUTH_REJECT;
                if (chain->table->set_message_length)
                {
                    chain->table->set_message_length = 0;
                    ssl_send_server_reply(ssl, server, chain->table->set_message);
                    pthread_mutex_unlock(&tablemutex);
					//MLog("UnLock: user relogin");
                }
                else
                {
                    pthread_mutex_unlock(&tablemutex);
					//MLog("UnLock: user relogin");
                    ssl_send_server_reply(ssl, server, "Relogin failed:1");
                }
            }
            else
            {
                if (((time(NULL) - chain->table->update_time)
                        >= USER_OFFLINE_TIME) &&
						(strcmp(chain->table->ipaddr, ipaddr) == 0))
                {
                    Vdebug(DEBUG_DATE, "[user login]Accept relogin %s", name);
                    chain->table->packet_id = 0;
                    chain->table->update_time = time(NULL);
                    chain->table->relogin_times++;
                    server->type = SERVER_AUTH_REPLY;
                    server->down_rate = chain->table->download_rate_limit;
                    server->up_rate = chain->table->upload_rate_limit;
                    server->user_type = chain->table->user_type;
                    memcpy(server->secret, chain->table->secret, UDP_PACKET_SECRET_KEY_LENGTH);
                    server->table_id = chain->id;
                    pthread_mutex_unlock(&tablemutex);
					//MLog("UnLock: user relogin");
                    ssl_send_server_reply(ssl, server, "Relogin successful");
                }
                else
                {
                    pthread_mutex_unlock(&tablemutex);
					//MLog("UnLock: user relogin");
                    Vdebug(DEBUG_DATE, "[user login]Deny relogin: %s, table too new or not match ip", name);
                    server->type = SERVER_AUTH_REJECT;
                    ssl_send_server_reply(ssl, server, "Relogin failed:2");
                }
            }
			break;
        }
		else if (client.radversion >= 200)
		{
			// use radius login
			pthread_mutex_unlock(&tablemutex);
			Vdebug(DEBUG_DATE, "[user login]relogin: %s, use radius login", name);
		}
        else
        {
            pthread_mutex_unlock(&tablemutex);
            Vdebug(DEBUG_DATE, "[user login]Deny relogin: %s, no table found", name);
            server->type = SERVER_AUTH_REJECT;
            ssl_send_server_reply(ssl, server, "Relogin failed");
			break;
        }*/
    case CLIENT_AUTH_REQUEST:
        //sprintf(iptemp, "Veno-Client-Ipaddr = %s;", ipaddr);
        pthread_mutex_lock(&tablemutex);
		//MLog("Lock: user login");
        /*if (auth_user_check(name) == 1)
        {
            Vdebug(DEBUG_DATE, "[user login]User %s auth too often, reject it", name);
            pthread_mutex_unlock(&tablemutex);
			//MLog("UnLock: user login");
            server->type = SERVER_AUTH_REJECT;
            ssl_send_server_reply(ssl, server, server_reply_auth_too_often);
            break;
        }*/		
        chain = new_table_init(name, pass, ipaddr, login_type, v);
        if (!chain)
        {
            pthread_mutex_unlock(&tablemutex);
			//MLog("UnLock: user login");
            server->type = SERVER_AUTH_REJECT;
            ssl_send_server_reply(ssl, server, server_reply_max_users);
            break;
        }
        pthread_mutex_unlock(&tablemutex);		
		//MLog("UnLock: user login");
        radius_auth_user(ssl, chain, server);
        break;
    }
thread_end:
	//DLog("User Leave Login: %s", name);
	    //printf("Thread (pid = %u) exit, closing sock %d\n", (unsigned int)pthread_self(), sock);
    SSL_shutdown(ssl);
    SSL_free(ssl);
    return NULL;
}


void *udp_thread(void *arg)
{
    int AmountRead;
    unsigned int FromLen;
    struct sockaddr_storage From;
    char sztmp[UDP_PACKET_MAX_LENGTH];
    char *buf;
    struct udp_query_queue *queue;
    pthread_t udp_packet_thread;

    if ((Serv_UDP_Sock = open_socket(PF_INET6, UDP_Port, SOCK_DGRAM)) == -1)
    {
        Vdebug(DEBUG_MAIN, "[udp thread]error open server udp socket");
        return 0;
    }
    pthread_cond_init(&udp_cond,NULL);
    queue_number = 0;
    head = NULL;
    tail = NULL;
    if (pthread_create( &udp_packet_thread, NULL, (void *)udp_packet_process, NULL) )
    {
        Vdebug(DEBUG_MAIN, "[udp thread]error creating udp packet process thread.");
        abort();
    }
    FromLen = sizeof (From);
    while (1)
    {
        memset(sztmp, 0, sizeof(sztmp));
        AmountRead = recvfrom(Serv_UDP_Sock, sztmp, UDP_PACKET_MAX_LENGTH, 0,
                              (struct sockaddr *) & From, &FromLen);
        if ((AmountRead == -1) || (AmountRead == 0))
        {
            Vdebug(DEBUG_BOTH, "[udp thread]recvfrom() failed with error.");
            continue;
        }
        if (AmountRead == UDP_PACKET_MAX_LENGTH)
        {
            Vdebug(DEBUG_DATE, "[udp thread]Receive too large udp packet.");
            continue;
        }
        // print_ipaddr(ipaddr, From);

        buf = malloc(UDP_PACKET_MAX_LENGTH);
        if (!buf)
        {
            continue;
        }
        memcpy(buf, sztmp, UDP_PACKET_MAX_LENGTH);
        queue = malloc(sizeof(udp_query_queue));
        if (!queue)
        {
            free(buf);
            continue;
        }
        memset(queue , 0, sizeof(udp_query_queue));
        queue->buf = (char *)buf;
        queue->next = NULL;
        memcpy(&queue->From, &From, sizeof(struct sockaddr_storage));
        queue->FromLen = FromLen;
        queue->packet_len = AmountRead;

        pthread_mutex_lock(&udp_mutex);
        queue_number++;
        queue->num = queue_number;
        if (!head)
        {
            head = queue;
            tail = queue;
            pthread_mutex_unlock(&udp_mutex);
            pthread_cond_signal(&udp_cond);
        }
        else
        {
            //assert(tail != NULL);
            tail->next = queue;
            tail = queue;
            pthread_mutex_unlock(&udp_mutex);
        }
    }
    return 0;
}

void change_to_daemon()
{
    pid_t pid, sid;
    /* Fork off the parent process */
    pid = fork();
    if (pid < 0)
    {
        exit(EXIT_FAILURE);
    }
    /* If we got a good PID, then
       we can exit the parent process. */
    if (pid > 0)
    {
        exit(EXIT_SUCCESS);
    }
    /* Change the file mode mask */
    umask(0);
    /* Open any logs here */
    /* Create a new SID for the child process */
    sid = setsid();
    if (sid < 0)
    {
        /* Log the failure */
        exit(EXIT_FAILURE);
    }
    /* Change the current working directory */
    if ((chdir("/")) < 0)
    {
        /* Log the failure */
        exit(EXIT_FAILURE);
    }
    /* Close out the standard file descriptors */
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);
}

int str2num (const char *str, int *num)
{
    if (!str) return 0;
    if (!strcmp(str, "YES")) *num = 1;
    else if (!strcmp(str, "NO")) *num = 0;
    else *num = atoi(str);
    return 1;
}

int get_server_config()
{
    radius_server_ipv6 = get_config("radius_server_ipv6");
    radius_server_ipv4 = get_config("radius_server_ipv4");
	radius_reserve_server_ipv6 = get_config("radius_reserve_server_ipv6"); 
	radius_reserve_server_ipv4 = get_config("radius_reserve_server_ipv4");
    if (!radius_server_ipv6 && !radius_server_ipv4)
    {
        Vdebug(DEBUG_MAIN, "[configure]Error :Nor radius server ipv4 or ipv6 address specified in config file. Server exit..");
        exit(1);
    }
    if (!(radius_server_ipv6 && radius_server_ipv4) == 1)
    {
        Vdebug(DEBUG_MAIN, "[configure]Warning...only one interface to radius server is set.");
    }
    if ((radius_default_af = get_config("radius_default_af")))
    {
        if (!strcmp(radius_default_af, "ipv6") && radius_server_ipv6)
        {
            radius_default_afnum = AF_INET6;
        }
        if (!strcmp(radius_default_af, "ipv4") && radius_server_ipv4)
        {
            radius_default_afnum = AF_INET;
        }
    }
    if (!radius_default_afnum)
    {
        radius_default_afnum = radius_server_ipv6 ? AF_INET6 : AF_INET;
        Vdebug(DEBUG_MAIN, "[configure]Default local interface set to %s", radius_default_afnum == AF_INET6 ? "IPv6" : "IPv4");
    }
    if (!(radius_shared_key = get_config("radius_shared_key")))
    {
        Vdebug(DEBUG_MAIN, "[configure]Error :No radius server shared key specified in config file. Server exit..");
        exit(1);
    }
    if (!(local_server_ipv6 = get_config("local_server_ipv6")))
    {
    }
    if (!(local_server_ipv4 = get_config("local_server_ipv4")))
    {
    }
    str2num(get_config("do_radius_test"), &do_radius_test);
    str2num(get_config("do_radius_account"), &do_radius_account);
    str2num(get_config("set_user_type"), &set_user_type);
    return 1;
}

void
usage()
{
    printf("My radius client : Usage\n");
    printf("-d : start as daemon\n");
    exit(1);
}

int main(int argc, char **argv)
{
	int daemon = 0;
    SSL_CTX *ctx;
    int  ServSock;
    pthread_t udp_pid;    
    int ch;

    while ((ch = getopt(argc, argv, "dhf:")) != -1)
    {
        switch (ch)
        {
        case 'h':
            usage();
        case 'd':
            daemon = 1;
            break;
        case 'f':
            num_config_pairs = read_config(optarg);
            if (num_config_pairs == -1)
            {
                exit(1);
            }
            break;
        default:
            usage();
        }
    }
    if (num_config_pairs == -2)
        if ((num_config_pairs = read_config("default.conf")) == -1)
        {
            fprintf(stdout, "Error...No configuration file is used\n");
            exit(1);
        }
    get_server_config();
    fprintf(stdout, "\n.....Start my nas radius server, version %s.....\n", SERVER_VERSION);
    /* Ignore the SIGPIPE signal in case a client exit earlier */
    signal(SIGPIPE, SIG_IGN);

    if (daemon == 1)
    {
        fprintf(stdout, "Server ready to start. Now switch to daemon model...\n");
        change_to_daemon();
    }

	debug = !daemon;

	LogInit ();
	MLog("Server start, version %s, daemon %d", SERVER_VERSION, daemon);
	DLog("Server start, version %s, daemon %d", SERVER_VERSION, daemon);
	
    /* Get local ip address from shell command ifconfig  */
    FILE * fp;
    char *charbuffer;
    void * charn;
    if (!local_server_ipv4)
    {
        fp = popen("ifconfig|grep -o -P '(?<=inet addr:)(?!127)\\b([0-9]{1,3}\\.){3}[0-9]{1,3}' -m 1","r");
        charbuffer = malloc(64);
        local_server_ipv4 = charbuffer;
        if (!charbuffer)
        {
            Vdebug(DEBUG_MAIN, "[main process]Error malloc, exit");
            exit(1);
        }
        charn = fgets(charbuffer,64,fp);
        pclose(fp);
    }
    if (!local_server_ipv6)
    {
        fp = popen("ifconfig|grep -o -P '(?<=inet6 addr:\\s)(?!fe80)(?!::)[0-90-z:]*' -m 1","r");
        charbuffer = malloc(64);
        local_server_ipv6 = charbuffer;
        if (!charbuffer)
        {
            Vdebug(DEBUG_MAIN, "[main process]Error malloc, exit");
            exit(1);
        }
        charn = fgets(charbuffer,64,fp);
        pclose(fp);
    }

    if ((ctx = ssl_init()) == NULL)
    {
        Vdebug(DEBUG_MAIN, "[main process]error set up ssl module");
        return 0;
    }
    if ((ServSock = open_socket(PF_INET6, TCP_Port, SOCK_STREAM)) == -1)
    {
        Vdebug(DEBUG_MAIN, "[main process]error open server tcp socket");
        return 0;
    }
    if (rad_init() != 1)
    {
        Vdebug(DEBUG_MAIN, "[main process]error initialize radius interface");
        exit(1);
    }
    table_chain_init();
    timer_init(&queue, (void *)user_timeout_callback, ACCOUNTING_CHECK_TIME, &tablemutex);
    rad_test();
    Vdebug(DEBUG_MAIN, "[main process]Starting http interface: Mongoose...");
    start_http();
    pthread_create(&udp_pid, NULL, &udp_thread, NULL);
    Vdebug(DEBUG_MAIN, "[main process]Begin to process requests...");
    while (1)
    {
        int ConnSock;
        SSL *ssl = 0;
        struct sockaddr_storage From;
        unsigned int FromLen = 0;
        // char ipaddr[40] ={0};
        pthread_t pid;

        memset(&From, 0, sizeof(struct sockaddr_storage));
        FromLen = sizeof(From);
        ConnSock = accept(ServSock, (struct sockaddr *)&From, &FromLen);
        // print_ipaddr(ipaddr, From);
#if USE_SSL_AUTHENTICATION
        ssl = SSL_new(ctx);
        if (ssl == NULL)
        {
            Vdebug(10, "Failed creating ssl\n");
            close(ConnSock);
            continue;
        }
        SSL_set_fd(ssl, ConnSock);
        SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
        pthread_create(&pid,NULL,&ssl_thread,(void *)ssl);
#else
        ssl = ssl;
        pthread_create(&pid,NULL, &ssl_thread, (void *)(unsigned long)ConnSock);
#endif
        pthread_detach(pid);
    }
    SSL_CTX_free(ctx);
}
